﻿using System;
using System.Collections.Generic;
using System.Text;
using Atechnology.glassCAD.Shapes.CutViewer;
using System.Drawing;
using Calculations.Calculations;

namespace Atechnology.glassCAD.Shapes
{
    public class FigureSolver
    {
        public static Arc[] GetInterpolationArcs(IFigure figure, int arcsCount, double precision)
        {
            List<Arc> arcs = new List<Arc>();
            float step = 1F / (float)arcsCount;
            for (float i = 0; i < 1; i += step)
            {
                Arc arc = FigureSolver.FindArcHalfDivisionMethod(figure, i, i + step, precision);
                arcs.Add(arc);
            }
            return arcs.ToArray();
        }

        private static Arc FindArcHalfDivisionMethod(IFigure figure, float startOffset, float endOffset, double epsilon)
        {
            PointF fstPoint = figure.GetOffsetPoint(startOffset);
            PointF secPoint = figure.GetOffsetPoint(endOffset);
            Arc fstArc = new Arc(fstPoint, secPoint, (float)GeometryCalculations.GetDistance(fstPoint, secPoint));
            Arc secArc = new Arc(fstPoint, secPoint, 3000);
            Arc middleArc = FigureSolver.GetMiddleArc(fstArc, secArc);     
            double currentDistance = FigureSolver.GetDistanceBetweenArcAndFigure(middleArc, figure, startOffset, endOffset);
            double prevDistance = double.MaxValue;
            double _epsilon = double.MaxValue;
            while (Math.Abs(prevDistance - currentDistance) > epsilon)
            {
                List<Arc> arcs = FigureSolver.FindCloserArcs(fstArc, secArc, middleArc, figure, startOffset, endOffset);
                fstArc = arcs[0];
                secArc = arcs[1];
                middleArc = FigureSolver.GetMiddleArc(fstArc, secArc);
                prevDistance = currentDistance;
                
                if (prevDistance < currentDistance) break;
                currentDistance = FigureSolver.GetDistanceBetweenArcAndFigure(middleArc, figure, startOffset, endOffset);
                _epsilon = Math.Abs(prevDistance - currentDistance);
            }
            
            return middleArc;
        }

        private static double GetDistanceBetweenArcAndFigure(Arc arc, IFigure figure, float startOffset, float endOffset)
        {
            PointF arcMiddlePoint = arc.GetPoint(0.5);
            PointF ellipseMiddlePoint = figure.GetOffsetPoint((startOffset + endOffset) / 2);
            return GeometryCalculations.GetDistance(arcMiddlePoint, ellipseMiddlePoint);
        }

        private static List<Arc> FindCloserArcs(Arc fstArc, Arc secArc, Arc middleArc, IFigure figure, float startOffset, float endOffset)
        {
            List<Arc> closerArcs = new List<Arc>();
            PointF figureMiddlePoint = figure.GetOffsetPoint((startOffset + endOffset) / 2);
            PointF fstArcMiddlePoint = fstArc.GetPoint(0.5);
            PointF secArcMiddlePoint = secArc.GetPoint(0.5);
            PointF middleArcMiddlePoint = middleArc.GetPoint(0.5);

            fstArc.Tag = GeometryCalculations.GetDistance(figureMiddlePoint, fstArcMiddlePoint);
            secArc.Tag = GeometryCalculations.GetDistance(figureMiddlePoint, secArcMiddlePoint);
            middleArc.Tag = GeometryCalculations.GetDistance(figureMiddlePoint, middleArcMiddlePoint);
            closerArcs.Add(fstArc);
            closerArcs.Add(secArc);
            closerArcs.Add(middleArc);
            closerArcs.Sort();
            closerArcs.RemoveAt(closerArcs.Count - 1);
            return closerArcs;
        }

        private static Arc GetMiddleArc(Arc fstArc, Arc secArc)
        {
            return new Arc(fstArc.StartPoint, secArc.EndPoint, (fstArc.Radius + secArc.Radius) / 2);
        }
    }
}
